using System;
using System.Collections.Generic;
using System.Linq;
using Urs.Core;
using Urs.Core.Data;
using Urs.Data.Domain.Stores;
using Urs.Data.Domain.Users;
using Urs.Data.Domain.Orders;
using Urs.Data.Domain.Payments;
using Urs.Data.Domain.Shipping;

namespace Urs.Services.Orders
{
    public partial class OrderService : IOrderService
    {
        #region Fields

        private readonly IRepository<Order> _orderRepository;
        private readonly IRepository<OrderItem> _opvRepository;
        private readonly IRepository<OrderNote> _orderNoteRepository;
        private readonly IRepository<Goods> _pRepository;
        private readonly IRepository<User> _userRepository;
        private readonly IRepository<AfterSales> _returnRequestRepository;
        #endregion

        #region Ctor

        public OrderService(IRepository<Order> orderRepository,
            IRepository<OrderItem> opvRepository,
            IRepository<OrderNote> orderNoteRepository,
            IRepository<Goods> pRepository,
            IRepository<User> userRepository,
            IRepository<AfterSales> returnRequestRepository)
        {
            _orderRepository = orderRepository;
            _opvRepository = opvRepository;
            _orderNoteRepository = orderNoteRepository;
            _pRepository = pRepository;
            _userRepository = userRepository;
            _returnRequestRepository = returnRequestRepository;
        }

        #endregion

        #region Methods

        #region Orders

        public virtual Order GetOrderById(int orderId)
        {
            if (orderId == 0)
                return null;

            return _orderRepository.GetById(orderId);
        }

        public virtual Order GetOrderByCode(string code)
        {
            if (string.IsNullOrEmpty(code))
                return null;

            return _orderRepository.Table.FirstOrDefault(o => o.Code == code);
        }

        public virtual IList<Order> GetOrdersByIds(int[] orderIds)
        {
            if (orderIds == null || orderIds.Length == 0)
                return new List<Order>();

            var query = from o in _orderRepository.Table
                        where orderIds.Contains(o.Id)
                        select o;
            var orders = query.ToList();
            var sortedOrders = new List<Order>();
            foreach (int id in orderIds)
            {
                var order = orders.Find(x => x.Id == id);
                if (order != null)
                    sortedOrders.Add(order);
            }
            return sortedOrders;
        }

        public virtual Order GetOrderByGuid(Guid orderGuid)
        {
            if (orderGuid == Guid.Empty)
                return null;

            var query = from o in _orderRepository.Table
                        where o.OrderGuid == orderGuid
                        select o;
            var order = query.FirstOrDefault();
            return order;
        }

        public virtual void DeleteOrder(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            order.Deleted = true;
            UpdateOrder(order);
        }

        public virtual IPagedList<Order> GetOrdersByAffiliateId(int affiliateId = 0, DateTime? startTime = null, DateTime? endTime = null,
             List<int> osIds = null, List<int> psIds = null, List<int> ssIds = null, int pageIndex = 0, int pageSize = int.MaxValue)
        {
            var query = _orderRepository.Table;
            if (startTime.HasValue)
                query = query.Where(o => startTime.Value <= o.CreateTime);
            if (endTime.HasValue)
                query = query.Where(o => endTime.Value >= o.CreateTime);
            if (affiliateId > 0)
                query = query.Where(o => o.AffiliateId == affiliateId);
            if (osIds != null && osIds.Any())
                query = query.Where(o => osIds.Contains(o.OrderStatusId));
            if (psIds != null && psIds.Any())
                query = query.Where(o => psIds.Contains(o.PaymentStatusId));
            if (ssIds != null && ssIds.Any())
                query = query.Where(o => ssIds.Contains(o.ShippingStatusId));

            query = query.Where(o => !o.Deleted);
            query = query.OrderByDescending(o => o.CreateTime);

            return new PagedList<Order>(query, pageIndex, pageSize);
        }

        public IPagedList<Order> SearchOrders(int? userId = null, DateTime? startTime = null, DateTime? endTime = null,
            OrderStatus? os = null, List<int> psIds = null, List<int> ssIds = null,
          int pageIndex = 0, int pageSize = int.MaxValue, bool delete = false)
        {
            var query = _orderRepository.Table;

            if (userId.HasValue)
                query = query.Where(o => o.UserId == userId.Value);
            if (startTime.HasValue)
                query = query.Where(o => startTime.Value <= o.CreateTime);
            if (endTime.HasValue)
                query = query.Where(o => endTime.Value >= o.CreateTime);
            if (os.HasValue && (int)os.Value > 0)
                query = query.Where(o => o.OrderStatusId == (int)os.Value);
            if (psIds != null && psIds.Any())
                query = query.Where(o => psIds.Contains(o.PaymentStatusId));
            if (ssIds != null && ssIds.Any())
                query = query.Where(o => ssIds.Contains(o.ShippingStatusId));
            query = query.Where(o => o.Deleted == delete);
            query = query.OrderByDescending(o => o.CreateTime);

            return new PagedList<Order>(query, pageIndex, pageSize);
        }

        public virtual void InsertOrder(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            var code = string.Empty;
            do
            {
                code = DateTime.Now.ToString("yyMMdd") + CommonHelper.RandomCode(8);
            } while (GetOrderByCode(code) != null);
            order.Code = code;
            _orderRepository.Insert(order);
        }

        public virtual void UpdateOrder(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            _orderRepository.Update(order);
        }

        public virtual void DeleteOrderNote(OrderNote orderNote)
        {
            if (orderNote == null)
                throw new ArgumentNullException("orderNote");

            _orderNoteRepository.Delete(orderNote);
        }

        public virtual OrderItem GetOrderGoodsById(int orderGoodsId)
        {
            if (orderGoodsId == 0)
                return null;

            return _opvRepository.GetById(orderGoodsId);
        }

        public virtual OrderItem GetOrderGoodsByGuid(Guid orderGoodsGuid)
        {
            if (orderGoodsGuid == Guid.Empty)
                return null;

            var query = from opv in _opvRepository.Table
                        where opv.OrderItemGuid == orderGoodsGuid
                        select opv;
            var orderGoods = query.FirstOrDefault();
            return orderGoods;
        }

        public virtual IList<OrderItem> GetAllorderItems(int? orderId,
            int? userId, DateTime? startTime, DateTime? endTime,
            OrderStatus? os, PaymentStatus? ps, ShippingStatus? ss,
            bool loadDownloableGoodssOnly)
        {
            int? orderStatusId = null;
            if (os.HasValue)
                orderStatusId = (int)os.Value;

            int? paymentStatusId = null;
            if (ps.HasValue)
                paymentStatusId = (int)ps.Value;

            int? shippingStatusId = null;
            if (ss.HasValue)
                shippingStatusId = (int)ss.Value;


            var query = from opv in _opvRepository.Table
                        join o in _orderRepository.Table on opv.OrderId equals o.Id
                        join p in _pRepository.Table on opv.GoodsId equals p.Id
                        where (!orderId.HasValue || orderId.Value == 0 || orderId == o.Id) &&
                        (!userId.HasValue || userId.Value == 0 || userId == o.UserId) &&
                        (!startTime.HasValue || startTime.Value <= o.CreateTime) &&
                        (!endTime.HasValue || endTime.Value >= o.CreateTime) &&
                        (!orderStatusId.HasValue || orderStatusId == o.OrderStatusId) &&
                        (!paymentStatusId.HasValue || paymentStatusId.Value == o.PaymentStatusId) &&
                        (!shippingStatusId.HasValue || shippingStatusId.Value == o.ShippingStatusId) &&
                        !o.Deleted
                        orderby o.CreateTime descending, opv.Id
                        select opv;

            var orderItems = query.ToList();
            return orderItems;
        }

        public virtual void DeleteOrderGoods(OrderItem orderGoods)
        {
            if (orderGoods == null)
                throw new ArgumentNullException("orderGoodsVariant");

            _opvRepository.Delete(orderGoods);
        }

        public int GetOrderCount(int userId, OrderStatus? os)
        {
            var query = _orderRepository.Table;
            query = query.Where(q => q.UserId == userId);

            int? orderStatusId = null;
            if (os.HasValue)
                orderStatusId = (int)os.Value;

            if (orderStatusId.HasValue)
                query = query.Where(o => o.OrderStatusId == orderStatusId.Value);


            query = query.Where(q => !q.Deleted);

            return query.Count();
        }
        public decimal GetOrderTotal(int userId, OrderStatus? os)
        {
            var query = _orderRepository.Table;
            query = query.Where(q => q.UserId == userId);

            int? orderStatusId = null;
            if (os.HasValue)
                orderStatusId = (int)os.Value;

            if (orderStatusId.HasValue)
                query = query.Where(o => o.OrderStatusId == orderStatusId.Value);


            query = query.Where(q => !q.Deleted);
            var a = query.ToList();
            return a.Sum(q => q.OrderTotal);
        }

        #endregion

        #region Return requests
        public virtual void InsertAfterSales(AfterSales returnRequest)
        {
            if (returnRequest == null)
                throw new ArgumentNullException("returnRequest");

            returnRequest.CreateTime = DateTime.Now;
            _returnRequestRepository.Insert(returnRequest);
        }
        public virtual void UpdateAfterSales(AfterSales returnRequest)
        {
            if (returnRequest == null)
                throw new ArgumentNullException("returnRequest");

            _returnRequestRepository.Update(returnRequest);
        }
        public virtual void DeleteAfterSales(AfterSales returnRequest)
        {
            if (returnRequest == null)
                throw new ArgumentNullException("returnRequest");

            _returnRequestRepository.Delete(returnRequest);
        }

        public virtual AfterSales GetAfterSalesById(int returnRequestId)
        {
            if (returnRequestId == 0)
                return null;

            return _returnRequestRepository.GetById(returnRequestId);
        }

        public virtual IList<AfterSales> GetAfterSalesByOrderId(int orderId)
        {
            if (orderId == 0)
                return new List<AfterSales>();

            return _returnRequestRepository.Table.Where(q => q.OrderId == orderId).ToList();
        }

        public virtual IPagedList<AfterSales> SearchAfterSales(int userId,
            int orderGoodsId, AfterSalesStatus? rs,
            int pageIndex, int pageSize)
        {
            var query = _returnRequestRepository.Table;
            if (userId > 0)
                query = query.Where(rr => userId == rr.UserId);
            if (rs.HasValue && rs.Value > 0)
            {
                int returnStatusId = (int)rs.Value;
                query = query.Where(rr => rr.AfterSalesStatusId == returnStatusId);
            }
            if (orderGoodsId > 0)
                query = query.Where(rr => rr.OrderItemId == orderGoodsId);

            query = query.OrderByDescending(rr => rr.CreateTime).ThenByDescending(rr => rr.Id);


            var returnRequests = new PagedList<AfterSales>(query, pageIndex, pageSize);
            return returnRequests;
        }

        public int GetRetrunRequestCount(OrderItem op, User user)
        {
            var list = _returnRequestRepository.Table.Where(rr => rr.OrderItemId == op.Id && rr.UserId == user.Id && rr.AfterSalesStatusId != (int)AfterSalesStatus.Cancelled);
            if (list.Count() == 0)
            {
                return 0;
            }
            else
            {
                return list.Sum(rr => rr.Quantity);
            }
        }

        public int GetAfterSalesCount(int userId, AfterSalesStatus? rrs)
        {
            var query = _returnRequestRepository.Table;
            query = query.Where(q => q.UserId == userId);

            int? rrStatusId = null;
            if (rrs.HasValue)
                rrStatusId = (int)rrs.Value;

            if (rrStatusId.HasValue)
                query = query.Where(o => o.AfterSalesStatusId == rrStatusId.Value);

            return query.Count();
        }
        #endregion

        #endregion


    }
}
